{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Part 12: 在加密数据上训练加密神经网络\n",
    "\n",
    "在此笔记本中，我们将使用到目前为止所学的所有技术来执行神经网络训练（和预测），同时对模型和数据进行加密。\n",
    "\n",
    "特别是，我们介绍了可用于加密计算的自定义Autograd引擎。\n",
    "\n",
    "作者:\n",
    "- Andrew Trask - Twitter: [@iamtrask](https://twitter.com/iamtrask)\n",
    "- Jason Paumier - Github: [@Jasopaum](https://github.com/Jasopaum)\n",
    "- Théo Ryffel - Twitter: [@theoryffel](https://twitter.com/theoryffel)\n",
    "\n",
    "中文版译者：\n",
    "- Hou Wei - github：[@dljgs1](https://github.com/dljgs1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第1步: 创建工作机和玩具数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import torch\n",
    "import torch.nn as nn\n",
    "import torch.nn.functional as F\n",
    "import torch.optim as optim\n",
    "import syft as sy"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 设置好所需\n",
    "hook = sy.TorchHook(torch) \n",
    "\n",
    "alice = sy.VirtualWorker(id=\"alice\", hook=hook)\n",
    "bob = sy.VirtualWorker(id=\"bob\", hook=hook)\n",
    "james = sy.VirtualWorker(id=\"james\", hook=hook)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 一个玩具数据集\n",
    "data = torch.tensor([[0,0],[0,1],[1,0],[1,1.]])\n",
    "target = torch.tensor([[0],[0],[1],[1.]])\n",
    "\n",
    "# 一个玩具模型\n",
    "class Net(nn.Module):\n",
    "    def __init__(self):\n",
    "        super(Net, self).__init__()\n",
    "        self.fc1 = nn.Linear(2, 2)\n",
    "        self.fc2 = nn.Linear(2, 1)\n",
    "\n",
    "    def forward(self, x):\n",
    "        x = self.fc1(x)\n",
    "        x = F.relu(x)\n",
    "        x = self.fc2(x)\n",
    "        return x\n",
    "model = Net()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第2步: 对模型和数据加密\n",
    "\n",
    "加密分为两个步骤。 由于安全多方计算仅适用于整数，因此为了对带小数点的数字（例如权重和激活数）进行运算，我们需要使用固定精度对所有数字进行编码，这将为我们提供几位十进制精度。 我们通过调用.fix_precision()来实现。\n",
    "\n",
    "然后，我们可以像调用其他演示一样调用.share()，它将通过在Alice和Bob之间共享它们来加密所有值。 请注意，我们还将require_grad设置为True，这也为加密数据添加了一种特殊的autograd方法。 确实，由于安全多方计算不适用于浮点值，因此我们无法使用通常的PyTorch自动分级。因此，我们需要添加一个特殊的AutogradTensor节点来计算梯度图以进行反向传播。您可以打印任何此元素以查看其包含AutogradTensor。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# We encode everything\n",
    "data = data.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)\n",
    "target = target.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)\n",
    "model = model.fix_precision().share(bob, alice, crypto_provider=james, requires_grad=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print(data)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第3步: 训练\n",
    "\n",
    "现在我们可以使用简单的张量逻辑进行训练。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "opt = optim.SGD(params=model.parameters(),lr=0.1).fix_precision()\n",
    "\n",
    "for iter in range(20):\n",
    "    # 1) erase previous gradients (if they exist)\n",
    "    opt.zero_grad()\n",
    "\n",
    "    # 2) make a prediction\n",
    "    pred = model(data)\n",
    "\n",
    "    # 3) calculate how much we missed\n",
    "    loss = ((pred - target)**2).sum()\n",
    "\n",
    "    # 4) figure out which weights caused us to miss\n",
    "    loss.backward()\n",
    "\n",
    "    # 5) change those weights\n",
    "    opt.step()\n",
    "\n",
    "    # 6) print our progress\n",
    "    print(loss.get().float_precision())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "损失确实减少了！"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 固定精度的影响\n",
    "\n",
    "您可能想知道加密所有内容如何影响不断减少的损失。实际上，由于理论计算是相同的，因此数字非常接近非加密训练。您可以通过运行相同的示例来验证这一点，而无需加密，并且可以对模型进行确定性的初始化，例如在模型__init__中：\n",
    "\n",
    "You might wonder how encrypting everything impacts the decreasing loss. Actually, because the theoretical computation is the same, the numbers are very close to non-encrypted training. You can verify this by running the same example without encryption and with a deterministic initialisation of the model like this one in the model `__init__`:\n",
    "```\n",
    "with torch.no_grad():\n",
    "    self.fc1.weight.set_(torch.tensor([[ 0.0738, -0.2109],[-0.1579,  0.3174]], requires_grad=True))\n",
    "    self.fc1.bias.set_(torch.tensor([0.,0.1], requires_grad=True))\n",
    "    self.fc2.weight.set_(torch.tensor([[-0.5368,  0.7050]], requires_grad=True))\n",
    "    self.fc2.bias.set_(torch.tensor([-0.0343], requires_grad=True))\n",
    "```\n",
    "\n",
    "您可能会观察到的细微差异是由于在转换为固定精度时对值进行了四舍五入。 默认的`precision_fractional`为3，如果将其降低到2，则明文训练的差异会增加，而如果选择`precision_fractional = 4`，则差异会减小。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 恭喜!!! 是时候加入社区了!\n",
    "\n",
    "祝贺您完成本笔记本教程！ 如果您喜欢此方法，并希望加入保护隐私、去中心化AI和AI供应链（数据）所有权的运动，则可以通过以下方式做到这一点！\n",
    "\n",
    "### 给 PySyft 加星\n",
    "\n",
    "帮助我们的社区的最简单方法是仅通过给GitHub存储库加注星标！ 这有助于提高人们对我们正在构建的出色工具的认识。\n",
    "\n",
    "- [Star PySyft](https://github.com/OpenMined/PySyft)\n",
    "\n",
    "\n",
    "### 加入我们的 Slack!\n",
    "\n",
    "保持最新进展的最佳方法是加入我们的社区！ 您可以通过填写以下表格来做到这一点[http://slack.openmined.org](http://slack.openmined.org)\n",
    "\n",
    "### 加入代码项目!\n",
    "\n",
    "对我们的社区做出贡献的最好方法是成为代码贡献者！ 您随时可以转到PySyft GitHub的Issue页面并过滤“projects”。这将向您显示所有概述，选择您可以加入的项目！如果您不想加入项目，但是想做一些编码，则还可以通过搜索标记为“good first issue”的GitHub问题来寻找更多的“一次性”微型项目。\n",
    "\n",
    "- [PySyft Projects](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3AProject)\n",
    "- [Good First Issue Tickets](https://github.com/OpenMined/PySyft/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22)\n",
    "\n",
    "### 捐赠\n",
    "\n",
    "如果您没有时间为我们的代码库做贡献，但仍想提供支持，那么您也可以成为Open Collective的支持者。所有捐款都将用于我们的网络托管和其他社区支出，例如黑客马拉松和聚会！\n",
    "\n",
    "[OpenMined's Open Collective Page](https://opencollective.com/openmined)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.4"
  },
  "latex_envs": {
   "LaTeX_envs_menu_present": true,
   "autoclose": false,
   "autocomplete": true,
   "bibliofile": "biblio.bib",
   "cite_by": "apalike",
   "current_citInitial": 1,
   "eqLabelWithNumbers": true,
   "eqNumInitial": 1,
   "hotkeys": {
    "equation": "Ctrl-E",
    "itemize": "Ctrl-I"
   },
   "labels_anchors": false,
   "latex_user_defs": false,
   "report_style_numbering": false,
   "user_envs_cfg": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
